package wkt;

import cn.hutool.core.text.CharSequenceUtil;
import lombok.extern.slf4j.Slf4j;
import net.xnzn.framework.config.exception.CodedException;
import net.xnzn.framework.config.response.ResponseWrapper;
import net.xnzn.framework.secure.filter.exception.LacksHeaderException;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.MDC;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.web.util.WebUtils;

import static net.xnzn.framework.config.TraceIdConfigurer.TRACE_KEY;

@Slf4j
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE + 24)
@MapperScan(basePackages = {"wkt","wx"}, annotationClass = Mapper.class, nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
@SpringBootApplication(scanBasePackages = {"wkt","wx"}, nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class ApiApplication extends ResponseEntityExceptionHandler {

	public static void main(String[] args) {
		SpringApplication.run(ApiApplication.class, args);
	}
	@ExceptionHandler(LacksHeaderException.class)
	ResponseEntity<Object> handleLacksHeaderException(Exception ex, WebRequest request) {
		return handleException(ex, ex.getMessage(), new HttpHeaders(), HttpStatus.UNAUTHORIZED.value(), request);
	}

	private static ResponseEntity<Object> handleException(Exception ex, @Nullable Object body, HttpHeaders headers, int status, WebRequest request) {
		if (HttpStatus.INTERNAL_SERVER_ERROR.value() == status) {
			request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, RequestAttributes.SCOPE_REQUEST);
		}

		String message = logException(ex, status);
		ResponseWrapper<?> fail = ResponseWrapper.fails(
				ex instanceof CodedException ? ((CodedException) ex).getCode() : null,
				body == null ? message : body.toString()
		);
		return new ResponseEntity<>(fail, headers, status);
	}

	private static String logException(Exception ex, int status) {
		String message = CharSequenceUtil.firstNonBlank(ex.getCause() != null ? ex.getCause().getMessage() : ex.getMessage(), "Error occurred while request processing");

		if (ex instanceof CodedException) {
			log.error("Business broken: {}", ex.getMessage());
			return message;
		}

		if (status < 500) {
			log.warn("Error occurred: {}", message);
			return "Client error occurred: " + CharSequenceUtil.nullToDefault(MDC.get(TRACE_KEY), "NoTraceIdFound");
		}

		log.error("Error occurred", ex);
		return "Server error occurred: " + CharSequenceUtil.nullToDefault(MDC.get(TRACE_KEY), "NoTraceIdFound");
	}
}
